
/*
 * Copyright (C) Micah Hisa<mail@xuefeng.org>
 */

#include <ngx_config.h>
#include <ngx_core.h>
#include <ngx_http.h>

typedef struct {
    ngx_uint_t      mod_num;
    ngx_keyval_t    url; 
} ngx_http_aclad_conf_t;

static ngx_http_aclad_conf_t ngx_http_aclad_conf_ctx = {
    100, { ngx_string("Location"), ngx_string("http://www.ad.com/show_ad.php?act=random") } 
};

static ngx_http_output_header_filter_pt  ngx_http_next_header_filter;

static ngx_int_t ngx_http_aclad_filter_init(ngx_conf_t *conf);
static char *ngx_http_aclad_hook(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);

static ngx_command_t ngx_http_aclad_commands[] = {
    {
        ngx_string("aclad_hook"),
        NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_HTTP_SIF_CONF|NGX_CONF_TAKE2,
        ngx_http_aclad_hook,
        0,
        0,
        NULL
    },
	ngx_null_command
};

static ngx_http_module_t ngx_http_aclad_module_ctx = {
	NULL,                          /* preconfiguration */
    ngx_http_aclad_filter_init,    /* postconfiguration */

	NULL,                          /* create main configuration */
	NULL,                          /* init main configuration */

	NULL,                          /* create server configuration */
	NULL,                          /* merge server configuration */

	NULL,                          /* create location configuration */
	NULL                           /* merge location configuration */
};

ngx_module_t ngx_http_aclad_module = {
	NGX_MODULE_V1,
	&ngx_http_aclad_module_ctx,    /* module context */
	ngx_http_aclad_commands,       /* module directives */
	NGX_HTTP_MODULE,               /* module type */
	NULL,                          /* init master */
	NULL,                          /* init module */
	NULL,                          /* init process */
	NULL,                          /* init thread */
	NULL,                          /* exit thread */
	NULL,                          /* exit process */
	NULL,                          /* exit master */
	NGX_MODULE_V1_PADDING
};

static ngx_int_t ngx_http_aclad_handler(ngx_http_request_t *r) {

    if (1 != rand() % ngx_http_aclad_conf_ctx.mod_num) {
        return NGX_DECLINED;
    }

    r->headers_out.status               = NGX_HTTP_MOVED_TEMPORARILY;
    r->headers_out.charset.len          = 0;
    r->headers_out.location             = ngx_list_push(&r->headers_out.headers);
    r->headers_out.location->hash       = 1;
    r->headers_out.location->key.len    = ngx_http_aclad_conf_ctx.url.key.len;
    r->headers_out.location->key.data   = ngx_http_aclad_conf_ctx.url.key.data;
    r->headers_out.location->value.len  = ngx_http_aclad_conf_ctx.url.value.len;
    r->headers_out.location->value.data = ngx_http_aclad_conf_ctx.url.value.data;

    if (NGX_ERROR == ngx_http_special_response_handler(r, NGX_HTTP_MOVED_TEMPORARILY)) {
        return NGX_ERROR;
    }

    return NGX_DONE;
}

static char* ngx_http_aclad_hook(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) {

    ngx_str_t *str;

    if (cf->args->nelts == 3) {
        str = &((ngx_str_t*)cf->args->elts)[1];
        ngx_http_aclad_conf_ctx.mod_num = ngx_atoi(str->data, str->len);

        str = &((ngx_str_t*)cf->args->elts)[2];
        ngx_http_aclad_conf_ctx.url.value.len  = str->len;
        ngx_http_aclad_conf_ctx.url.value.data = ngx_pstrdup(cf->pool, str);
    }

    return NGX_CONF_OK;
}

static ngx_int_t ngx_http_aclad_filter_init(ngx_conf_t *cf) {

    ngx_http_handler_pt        *h;
    ngx_http_core_main_conf_t  *cmcf;

    cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);

    h = ngx_array_push(&cmcf->phases[NGX_HTTP_ACCESS_PHASE].handlers);
    if (h == NULL) {
        return NGX_ERROR;
    }

    *h = ngx_http_aclad_handler;

    return NGX_OK;
}

